package com.cci.kangdao.service.impl;

import com.cci.kangdao.common.ApplicationContextUtils;
import com.cci.kangdao.common.RedisKeys;
import com.cci.kangdao.common.type.NotifyChannelType;
import com.cci.kangdao.common.type.NotifyMannerType;
import com.cci.kangdao.common.type.NotifyModelType;
import com.cci.kangdao.dao.*;
import com.cci.kangdao.dao.model.*;
import com.cci.kangdao.escalation.service.EscalationNotifyService;
import com.cci.kangdao.fieldService.service.FieldServiceNotifyService;
import com.cci.kangdao.redis.RedisClientUtils;
import com.cci.kangdao.service.NotifyConfigService;
import com.cci.kangdao.utilTool.*;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author William Du
 * @date 2020/5/13
 */
@Service
public class NotifyConfigServiceImpl implements NotifyConfigService {

    private final static Logger LOGGER = Logger.getLogger(NotifyConfigServiceImpl.class);

    private static Pattern MESSAGE_PATTERN = Pattern.compile("(?<=\\$\\{)(.+?)(?=})");

    @Resource
    private NotifyConfigTDao notifyConfigTDao;

    @Resource
    private NotifyConfigMannerTDao notifyConfigMannerTDao;

    @Resource
    private NotifyConfigReceiverTDao notifyConfigReceiverTDao;

    @Resource
    private EscalationNotifyService escalationNotifyService;

    @Resource
    private FieldServiceNotifyService fieldServiceNotifyService;

    @Resource
    private CommonNotifyRecordTDao commonNotifyRecordTDao;

    @Resource
    private RedisClientUtils redisClientUtils;
    @Resource
    private RelationShipTDao relationShipTDao;


    @Override
    public void doNotify(String channel, String model, String doServiceName, String doMethodName, Long uniqueKeyId) {
        try {
            // 获取监听该方法的所有实时通知
            List<NotifyConfigT> realTimeList = notifyConfigTDao.selectRealTimeList(channel, model, doServiceName, doMethodName);
            LOGGER.error("NotifyConfigT：channel"+channel+"，model"+model+"获取通知的类"+doServiceName+"获取通知的方法"+doMethodName);
            if (CollectionUtils.isNotEmpty(realTimeList)) {
                for (NotifyConfigT notifyConfigT : realTimeList) {
                    doNotify(notifyConfigT, uniqueKeyId);
                }
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    /**
     * 新消息推送
     * @param listenService
     * @param escalationOrderId
     */
    @Override
    public void xinDoNotify(String listenService,String listenMethod, Long escalationOrderId) {
        // 获取监听该方法的所有实时通知
        List<NotifyConfigT> realTimeList = notifyConfigTDao.selectXinRealTimeList(NotifyChannelType.CCI.getCode(), NotifyModelType.ESCALATION.getCode(), listenService, listenMethod);
        LOGGER.error("NotifyConfigT：获取通知的类"+listenService+"获取通知的方法"+listenMethod);
        if (CollectionUtils.isNotEmpty(realTimeList)) {
            for (NotifyConfigT notifyConfigT : realTimeList) {
                doNotify(notifyConfigT, escalationOrderId);
            }
        }
    }

    private void doNotify(NotifyConfigT notifyConfigT, Long uniqueKeyId) {
        Map<String, Object> dataMap = new HashMap<>();
        LOGGER.info("开始通知");
        if (StringUtils.isNotEmpty(notifyConfigT.getCustomService()) && StringUtils.isNotEmpty(notifyConfigT.getCustomMethod())) {
            try {
                dataMap = (Map<String, Object>) ApplicationContextUtils.runMethod(notifyConfigT.getCustomService(), notifyConfigT.getCustomMethod(), uniqueKeyId);
            } catch (Exception e) {
                LOGGER.error("获取通知数据集合报错：" + e.getMessage(), e);
            }
        } else {
            if (NotifyModelType.ESCALATION.getCode().equals(notifyConfigT.getModel())) {
                dataMap = escalationNotifyService.getEscalationData(uniqueKeyId);
            } else if (NotifyModelType.CFWO.getCode().equals(notifyConfigT.getModel())) {
                dataMap = fieldServiceNotifyService.getNotifyData(uniqueKeyId);
            }
        }
        LOGGER.info("dataMap：" + dataMap.toString());
        // 如果存在数据状态等设置，进行状态验证
        if (StringUtils.isNotEmpty(notifyConfigT.getKeyPoint())) {
            Integer dataKeyPointValue = MapUtils.getInteger(dataMap, notifyConfigT.getKeyPoint(), -1);
            if (!dataKeyPointValue.equals(notifyConfigT.getKeyPointValue())) {
                return;
            }
        }

        // 如果有频率限制，则进行频率判断逻辑
        Integer frequency = notifyConfigT.getFrequency();
        if (NumberUtils.isPositiveNum(frequency)) {
            List<CommonNotifyRecordT> notifyRecordTS = commonNotifyRecordTDao.selectListByOrderAndConfig(notifyConfigT.getChannel(), uniqueKeyId, notifyConfigT.getId());
            if (notifyRecordTS.size() >= frequency) {
                return;
            }
        }

        if (MapUtils.isNotEmpty(dataMap)) {
            List<NotifyConfigMannerT> mannerTList = notifyConfigMannerTDao.selectListByConfigId(notifyConfigT.getId());
            if (CollectionUtils.isNotEmpty(mannerTList)) {
                for (NotifyConfigMannerT manner : mannerTList) {
                    List<UserT> userTList = new ArrayList<>();
                    NotifyConfigReceiverT notifyConfigReceiverT = notifyConfigReceiverTDao.selectByPrimaryKey(manner.getReceiverConfigId());
                    if (null != notifyConfigReceiverT) {
                        try {
                            userTList = (List<UserT>) ApplicationContextUtils.runMethod(notifyConfigReceiverT.getProxyService(), notifyConfigReceiverT.getProxyMethod(), uniqueKeyId);
                        } catch (Exception e) {
                            LOGGER.error("获取通知用户列表报错：" + e.getMessage(), e);
                        }
                    }
                    LOGGER.error("获取通知用户列表：" + JsonUtils.toJsonString(userTList));
                    if (CollectionUtils.isNotEmpty(userTList)) {
                        if (NotifyMannerType.SMS.getCode().equals(manner.getSendType())) {
                            String content = mergeSendContent(manner.getContent(), dataMap);
                            sendSMS(notifyConfigT.getId(), notifyConfigT.getModel(), uniqueKeyId, userTList, content);
                        } else if (NotifyMannerType.APP.getCode().equals(manner.getSendType())) {
                            String title = mergeSendContent(manner.getTitle(), dataMap);
                            String content = mergeSendContent(manner.getContent(), dataMap);
                            push(notifyConfigT.getId(), notifyConfigT.getModel(), uniqueKeyId, userTList, title, content);
                        } else {
                            String title = mergeSendContent(manner.getTitle(), dataMap);
                            String content = mergeSendContent(manner.getContent(), dataMap);
                            sendEmail(notifyConfigT.getId(), notifyConfigT.getModel(), uniqueKeyId, userTList, title, content);
                        }
                    }
                }
            } else {
                LOGGER.error("通知方式列表，通知配置ID：" + notifyConfigT.getId());
            }
        } else {
            LOGGER.error("通知数据集合为空，通知数据：" + notifyConfigT.getChannel() + "|" + notifyConfigT.getModel() + "|" + uniqueKeyId);
        }
    }

    private String mergeSendContent(String sourceInfo, Map<String, Object> dataMap) {
        String mergeContent = sourceInfo;
        if (StringUtils.isNotEmpty(sourceInfo)) {
            Pattern pattern = Pattern.compile("(?<=\\$\\{)(.+?)(?=})");
            Matcher matcher = pattern.matcher(sourceInfo);
            while (matcher.find()) {
                String key = matcher.group();
                String data = MapUtils.getString(dataMap, key, "");
                mergeContent = mergeContent.replace("${" + key + "}", data);
            }
        }
        return mergeContent;
    }

    private void sendSMS(Long configId, String category, Long uniqueId, List<UserT> userTList, String content) {
        for (UserT userT : userTList) {
            SmsUtils.sendMessage(userT.getPhone(), content);
            CommonNotifyRecordT recordT = new CommonNotifyRecordT();
            recordT.setCategory(category);
            recordT.setOrderId(uniqueId);
            recordT.setConfigId(configId);
            recordT.setReceiverId(userT.getId());
            recordT.setContent(content);
            recordT.setStatus("1");
            recordT.setSendType(NotifyMannerType.SMS.getCode());
            recordT.setCreator(userT.getId());
            recordT.setCreateTime(LocalTimeUtil.getRealCurrentTime());
            commonNotifyRecordTDao.insertSelective(recordT);
        }
        System.out.println("发送短信：" + content + "|人数：" + userTList.size());
    }

    private void push(Long configId, String category, Long uniqueId, List<UserT> userTList, String title, String content) {
        for (UserT userT : userTList) {
            String clientId = redisClientUtils.hget(RedisKeys.geTuiKey(), userT.getUserName());
            if (StringUtils.isEmpty(clientId)) {
                // redis中不存在，查询数据库
                RelationShipT relationShipT = relationShipTDao.getClientIdByUserNameString(userT.getUserName());
                if (null != relationShipT) {
                    clientId = relationShipT.getClientId();
                }
            }

            CommonNotifyRecordT recordT = new CommonNotifyRecordT();
            recordT.setCategory(category);
            recordT.setOrderId(uniqueId);
            recordT.setConfigId(configId);
            recordT.setReceiverId(userT.getId());
            recordT.setContent(content);
            recordT.setFlag(0);
            recordT.setSendType(NotifyMannerType.APP.getCode());

            // ClientId不为空时，进行推送操作，为空时进行异常记录
            if (StringUtils.isNotEmpty(clientId)) {
                // 发送推送操作
                NotifyUtil.push2Single(clientId, title, content, 2, content);
                recordT.setStatus("1");
            } else {
                recordT.setStatus("2");
                recordT.setExceptionInfo("用户ClientId不存在");
            }

            recordT.setCreator(userT.getId());
            recordT.setCreateTime(LocalTimeUtil.getRealCurrentTime());
            commonNotifyRecordTDao.insertSelective(recordT);
        }
        System.out.println("发送推送：" + content + "|人数：" + userTList.size());
    }

    private void sendEmail(Long configId, String category, Long uniqueId, List<UserT> userTList, String title, String content) {
        for (UserT userT : userTList) {
            String email = userT.getEmail();

            CommonNotifyRecordT recordT = new CommonNotifyRecordT();
            recordT.setCategory(category);
            recordT.setOrderId(uniqueId);
            recordT.setConfigId(configId);
            recordT.setReceiverId(userT.getId());
            recordT.setContent(content);
            recordT.setFlag(0);
            recordT.setSendType(NotifyMannerType.EMAIL.getCode());
            if (StringUtils.isNotEmpty(email)) {
                try {
                    Thread t = Thread.currentThread();
                    String name = t.getName();
                    LOGGER.info("发送邮件开始："+name);
                    MailUtil.sendMail(email, title, content);
                    recordT.setStatus("1");
                    LOGGER.info("发送邮件结束："+name);
                } catch (Exception e) {
                    LOGGER.error(e.getMessage(), e);
                    recordT.setStatus("2");
                    recordT.setExceptionInfo("发送邮件发生异常：" + e.getMessage());
                }
            } else {
                recordT.setStatus("2");
                recordT.setExceptionInfo("接收人邮箱为空，无法发送，接收人手机号：" + userT.getPhone());
            }
            recordT.setCreator(userT.getId());
            recordT.setCreateTime(LocalTimeUtil.getRealCurrentTime());
            commonNotifyRecordTDao.insertSelective(recordT);
        }
    }


}
